/**
 * ReadXMLOrder.java
 *
 * Enterprise Java
 *
 * Author:  Matthew Braddy
 * Created: Oct 28, 2010
 *
 */

package java113.labs;

import org.xml.sax.*;
import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
import java.util.*;
import java.io.*;
import java.util.logging.*;
import java113.dataAccess.DataManager;

/**
 *
 * @author Matthew Braddy
 */

public class ReadXML extends DefaultHandler
{


    //used to hold the current contents of the xml that is being parsed
    private CharArrayWriter m_oContents;
    
    //insert group of instance variables here that will be used to fill with data as the xml is parsed
    private Object          m_oMyObject;  

    private Properties      properties;

    private Map             m_addresses;

    private Map             addresses;

    private Address         address;

    private Name            name;

    private Classification  classification;

    private int             counter;

    private Logger          logger;

    private DataManager     m_oDataManager;

    /**
     * Class constructor for this object
     */
    public ReadXML(Properties properties, DataManager m_oDataManager) {

        setProperties(properties);

        this.m_oDataManager = m_oDataManager;

        setCounter(0);

        addresses = new HashMap();

        logger = Logger.getLogger(properties.getProperty("logger"));

    }

    /**
     *
     * @return
     */
    public Properties getProperties() {

        return this.properties;

    }

    /**
     *
     * @param properties
     */
    public void setProperties(Properties properties) {

        this.properties = properties;

    }

    public void setAddresses(Map addresses) {

        this.addresses = addresses;

    }

    /**
     *
     * @return
     */
    public Map getAddresses() {

        return this.addresses;

    }

    /**
     *
     * @return
     */
    public int getCounter() {

        return this.counter;

    }

    /**
     *
     * @param counter
     */
    public void setCounter(int counter) {

        this.counter = counter;

    }

    private void incrementCounter() {

        this.counter++;

    }


    /**
     * Used to initialize the class and parse the XML
     *
     *  @param String strInXMLPath      full path to the XML
     */
    public void load() throws Exception
    {
    	InputStream oInputStream;

        //the following 5 lines of code are canned; they typically not change
        this.m_oContents = new CharArrayWriter();  //create a bucket for the current contents of the XML
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sp = spf.newSAXParser();
        ParserAdapter pa = new ParserAdapter(sp.getParser());
        pa.setContentHandler(this);

        //instantiate any instance variables here if you will be building some kind of collection

        //derive a stream from the file and parse
        oInputStream = new FileInputStream(properties.getProperty("xml.lab.file.input"));
        logger.log(Level.INFO,  (properties.getProperty("xml.lab.file.input") +
                " has been opened for reading."));

        pa.parse(new InputSource(oInputStream));  //parse() will parse the stream represented by the file in strInXMLPath
        logger.log(Level.INFO,  (properties.getProperty("xml.lab.file.input") +
                " has been parsed."));

        System.out.println(this.addresses.toString());

    }

    /**
     * Return my generated object
     */
    public Object getMyObject()
    {
        return this.m_oMyObject;
    }


    /**
     * This method is used to determine the start point of an element in an
     * XML stream as it is being parsed; method is called when the parser has identified the beginning of
     * an element; hence, it is called for each and every beginning element found in the XML
     *
     * @param String localName      the name of the element
     * @param Attributes attr               a map-like structure that contains all element attributes
     */
    @Override
    public void startElement(String namespaceURI, String localName, String qName, Attributes attr) throws SAXException
    {
        String strHold;
        this.m_oContents.reset();  //used to capture the current textual information for an element

        //here, we are checking the name of the elements that we are expecting to encounter in the XML; if an
        //element is encountered, then we will handle it; in our case, we may want to create an object instance and store it
        //since we will be using it; only elements that are currently being acted on are of interest; if we encounter an element
        //that we did not account for, then the data is lost as we will not do anything with it
        if(localName.equalsIgnoreCase("ADDRESS"))
        {

            address        = new Address();

            name           = new Name();

            classification = new Classification();

            incrementCounter();

            address.setId(counter);

            strHold = attr.getValue("name");

            if(strHold != null && strHold.trim ().length () > 0) {

                name.setId(counter);

                String[] strArray = strHold.split(" ");
                
                name.setFirst(strArray[0]);

                name.setLast(strArray[1]);

            }

            strHold = attr.getValue("type");

            if(strHold != null && strHold.trim ().length () > 0) {

                if (strHold.equalsIgnoreCase("person")) {

                    name.setClassification_id(1);

                } else {

                    name.setClassification_id(2);

                }

            }
            
        }
        
    }

    /**
     * This method is used to determine the end point of an element in an
     * XML stream as it is being parsed; it is called for each and every element that is closed in the
     * XML; the element data was stored in the m_oContents instance variable; we will extract the
     * accumulated text and place it where it belongs
     */
    @Override
    public void endElement(String namespaceURI, String localName, String qName) throws SAXException
    {
        String strHold;
        int key = 0;

        //again, look for the element name that tells us which element just closed
        if(localName.equalsIgnoreCase("ADDRESS")) {

            this.m_addresses = new HashMap();
            try {

                NameDAO nameDAO = new NameDAO(properties, m_oDataManager);
                key = nameDAO.setName(counter, name.getFirst(), name.getLast(), name.getClassification_id(), counter);

                AddressDAO addressDAO = new AddressDAO(properties, m_oDataManager);
                addressDAO.setAddress(counter, address.getStreet(), address.getCity(), address.getState(), address.getZip());

            } catch (Exception ex) {
                Logger.getLogger(ReadXML.class.getName()).log(Level.SEVERE, null, ex);
            }


            
            this.m_addresses.put((String)"name", this.name);
            this.m_addresses.put((String)"address", this.address);

            this.addresses.put(this.counter, this.m_addresses);

            

            this.address = null;// not sure if this will reset without clearing out the map!!
           
        } else if(localName.equalsIgnoreCase("STREET")) {

            //handle it as well
            strHold = this.m_oContents.toString();

            address.setStreet(strHold);

        } else if(localName.equalsIgnoreCase("CITY")) {

            //handle it as well
            strHold = this.m_oContents.toString();

            address.setCity(strHold);

        } else if(localName.equalsIgnoreCase("STATE")) {

            //handle it as well
            strHold = this.m_oContents.toString();

            address.setState(strHold);

        } else if(localName.equalsIgnoreCase("ZIP")) {

            //handle it as well
            strHold = this.m_oContents.toString();

            address.setZip(strHold);

        }

    }

    /**
     * Override methods of the DefaultHandler class to gain notification of SAX Events. See
     * org.xml.sax.ContentHandler for all available events
     *
     * This method is used to retrieve the characters in the XML stream
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException
    {
        this.m_oContents.write(ch, start, length);
    }

    

}